/**
 * FILE:  CW-QuickSearch.js
 *
 * Part of the Metavus digital collections platform
 * Copyright 2015-2020 Edward Almasy and Internet Scout Research Group
 * http://metavus.net
 *
 * @scout:eslint
 */

/**
* Create a new QuickSearch Object. Customizes the functionality of the generic
* jquery-ui-autocomplete to search a specific MetadataField (the FieldId param).
* @param ElementId String The html id of the input where the autocomplete should attach
* @param FieldId String The integer id of the MetaDataField associated with the input
* @param MultipleValues Boolean; if the field should accomodate multiple values
* @param CurrentValue string value to display for this field
* after it, or if we should deligate cloning to a later field.
*
* The QuickSearch requires HTML elements of the form generated by
* PrintQuickSearchField() defined in
* interface/default/include/F-PrintQuickSearchField.php
*
* Expects JSON responses from search handlers in either of these formats:
*
* failure (a single js object having 2 members):
*   {
*     success: false,
*     general_message: 'FAILURE MESSAGE HERE',
*   }
*
*
* success (an array of js objects each w/ 3 members):
*   [
*       { "label" : "HTML to display in the menu",
*         "value" : "Text to enter in search box when this item is selected",
*         "ItemId": ItemId
*        },
*   ]
*/

var QuickSearch; // (see definition below)
(function(){
    /**
     * Set up quick search event handlers to provide incremental search functionality.
     * @param Element el A div.mv-quicksearch to configure for quicksearching.
     */
    QuickSearch = function (el) {
        // extract our fieldid and grab the elements we'll want to manipulate
        var displayEl = $('.mv-quicksearch-display', el);

        // error out if this widget has been previously configured
        if (displayEl.autocomplete('instance') !== undefined) {
            throw 'Quicksearch already configured!';
        }

        // set the prompt up to display when a user selects the dropdown
        displayEl.on("focus", function() {
            handleFocusIn(el);
        });

        // when our search entry loses focus
        displayEl.on("focusout", function() {
            handleFocusOut(el);
        });

        // prevent the enter key from submitting
        displayEl.on("keydown", function(event) {
            if (event.keyCode == 13) {
                event.preventDefault();
                return false;
            }
            return true;
        });

        // adjust the height of the autocomplete textareas to fit its content
        displayEl.height(0);
        displayEl.height(Math.max(17, displayEl.prop('scrollHeight')));

        // set up autocomplete widget
        displayEl.autocomplete({
            minLength: 2,
            html: true,
            delay: 750,
            autoFocus: (el.attr('data-fieldid') !== "KeywordSearch"),
            response: function(event, ui) {
                autocompleteResponse(event, ui, el);
            },
            source: function (request, response) {
                autocompleteSource(request, response, el);
            },
            select: function (event, ui) {
                autocompleteSelect(event, ui, el);
            },
            focus: function(event) {
                event.preventDefault();
            },
            open: function() {
                $('.mv-quicksearch-moreresults').parent().parent().css('padding', 0);
            },
        });
    };

    // private helper functions for the QuickSearch functionality

    /**
     * React to a quicksearch textarea being focused by showing a
     *   search prompt and displaying the dropdown menu.
     * @param HtmlElement el Quicksearch container
     */
    function handleFocusIn(el) {
        var messageEl = $(".mv-quicksearch-message", el),
            menuEl = $(".mv-quicksearch-menu", el),
            displayEl = $('.mv-quicksearch-display', el);

        $(displayEl).data('prev_value', $(displayEl).val());
        if ($(displayEl).val().trim().length == 0) {
            messageEl.html("Type some keywords to begin searching.");
            messageEl.show();
            menuEl.show();
        }
    }

    /**
     * React when a quicksearch textarea loses focus by hiding the
     *   dropdown menu and restoring a previous selection if the user
     *   has not made a new selection
     * @param HtmlElement el Quicksearch container.
     */
    function handleFocusOut(el) {
        // extract our fieldid and grab the elements we'll want to manipulate
        var fieldId = el.attr('data-fieldid'),
            messageEl = $(".mv-quicksearch-message", el),
            menuEl = $(".mv-quicksearch-menu", el),
            displayEl = $('.mv-quicksearch-display', el),
            valueEl = $('.mv-quicksearch-value', el);

        // hide the container that shows search results
        menuEl.hide();
        messageEl.hide();

        // for keyword searches nothing else is needed
        if (fieldId === "KeywordSearch") {
            return;
        }

        // but for field value searches, check if we had a previous value
        if ($(displayEl).data('prev_value') !== undefined) {
            // if the user didn't just clear the current value,
            // but didn't select a new one
            if ($(displayEl).val().length > 0) {
                // reset to the last good value
                $(displayEl).val($(displayEl).data('prev_value'));
            } else {
                valueEl.val('');
            }

            // and forget the last value we had stored
            $(displayEl).removeData('prev_value');
        }
    }

    /**
     * React when results become available after searching, showing a
     *   'no results' message if necessary.
     * @see https://api.jqueryui.com/autocomplete/#event-response
     * @param Event event
     * @param jqueryUI ui object
     * @param HtmlElement el Quicksearch container
     */
    function autocompleteResponse(event, ui, el) {
        // extract our fieldid and grab the elements we'll want to manipulate
        var messageEl = $(".mv-quicksearch-message", el),
            menuEl = $(".mv-quicksearch-menu", el);

        if (ui.content.length == 0) {
            messageEl.html("No results found for <i>" + event.target.value + "</i>.");
            messageEl.show();
            menuEl.show();
        } else {
            messageEl.hide();
        }
    }

    /**
     * Source for autocompletion options, makes the appropriate ajax calls to get search results.
     * @see https://api.jqueryui.com/autocomplete/#option-source
     * @param object request query to autocomplete
     * @param response callback function provided by jquery-ui for updating the autocomplete widget
     * @param HtmlElement el Quicksearch container
     */
    function autocompleteSource(request, response, el) {
        var fieldId = el.attr('data-fieldid'),
            messageEl = $(".mv-quicksearch-message", el),
            menuEl = $(".mv-quicksearch-menu", el),
            displayEl = $('.mv-quicksearch-display', el);

        messageEl.html("Searching for <i>" + request.term + "</i>.");
        messageEl.show();
        menuEl.show();

        // determine which page by the search type
        var getParams = { SS: request.term };
        switch (fieldId) {
        case 'KeywordSearch' :
            getParams.P = "KeywordQuickSearchCallback" ;
            break;

        case 'UserSearch' :
            getParams.P = "UserQuickSearchCallback";
            break;

        default :
            getParams.P = "MetadataFieldQuickSearchCallback";
            getParams.MF = fieldId;
            break;
        }

        jQuery.get(
            CWIS_BASE_URL + "index.php", // eslint-disable-line no-undef
            getParams,
            function (reply) {
                response(reply);
            }
        );

        // adjust the height of the autocomplete textareas to fit its content
        displayEl.height(0);
        displayEl.height(Math.max(17, displayEl.prop('scrollHeight')));
    }

    /**
     * Handler for autocomplete select events. Updates HTML input
     *   element that stores the ID of the selected term and adds more
     *   dropdown menus if needed.
     * @see https://api.jqueryui.com/autocomplete/#event-select
     * @param Event event
     * @param jqueryUI ui object
     * @param HtmlElement el Quicksearch container
     */
    function autocompleteSelect(event, ui, el ){
        var fieldId = el.attr('data-fieldid'),
            menuEl = $(".mv-quicksearch-menu", el),
            displayEl = $('.mv-quicksearch-display', el),
            valueEl = $('.mv-quicksearch-value', el);
        if (fieldId == "KeywordSearch") {
            var ItemId = ui.item.ItemId;
            // if a resource was clicked, jump to that resource
            if (ItemId.length > 0) {
                event.preventDefault();
                window.location.assign(
                    CWIS_BASE_URL + "index.php?P=FullRecord&ID=" + ItemId.substring(1)); // eslint-disable-line no-undef
                return false;
            }
            return true;
        }

        event.preventDefault();

        // strip html, insert the value, remove our marker for the previous value
        valueEl.val(ui.item.ItemId);
        displayEl.val(ui.item.value.replace(/<\/?[^>]+(>|$)/g, ""));
        displayEl.removeData('prev_value');

        // hide the menu
        menuEl.hide();

        // see if we have a template row to clone
        var qsRowSelector = ".mv-quicksearch.mv-quicksearch-fieldid-" + fieldId;
        if ($(qsRowSelector + ".mv-quicksearch-template").length > 0){
            // determine if there are any empty containers aside from the
            // template row
            var emptyRows = $('.mv-quicksearch-value[value=""]',
                qsRowSelector + ":not(.mv-quicksearch-template)");

            // if there aren't any empty entries, create more
            if (emptyRows.length == 0) {
                var new_row = $(qsRowSelector + ".mv-quicksearch-template")
                    .clone()
                    .removeAttr('style')
                    .removeClass('mv-quicksearch-template')
                    .insertAfter(qsRowSelector + ":not(.mv-quicksearch-template):last");

                // connect it to the machine
                QuickSearch(new_row);
            }
        }

        // adjust the height of the autocomplete textareas to fit its content
        var prevHeight = displayEl.height();
        displayEl.height(0);
        displayEl.height(Math.max(prevHeight, displayEl.prop('scrollHeight')));

        return true;
    }
})();

$(document).ready(function() {
    var qsRowSelector = '.mv-quicksearch:not(.mv-quicksearch-template)';

    // hook up all the quicksearch elements on the page
    $(qsRowSelector).each(function(index, element){
        QuickSearch($(element));
    });

    // custom event to get the current list of selections
    // (see https://api.jquery.com/on/ )
    $(".mv-quicksearchset").on("mv:getselections", function() {
        var selections = [], usedTids = [];
        $(qsRowSelector, $(this)).each(function(index, element){
            var tid = $('input.mv-quicksearch-value', element).val(),
                name = $('textarea.mv-quicksearch-display', element).val();
            if (tid != '' && !usedTids.includes(tid) ) {
                selections.push({tid: tid, name: name});
                usedTids.push(tid);
            }
        });

        return selections;
    });

    // custom event to set form selections
    $(".mv-quicksearchset").on("mv:setselections", function(event, selections) {
        var tgtNumLists = selections.length + 1;

        // if we didn't have enough, add more
        while ($(qsRowSelector, $(this)).length < tgtNumLists) {
            // add a new quicksearch row after the last such row in our container
            $(qsRowSelector, $(this)).last().clone(true).insertAfter($(qsRowSelector, $(this)).last());
        }
        // if we had too many, delete the extras
        while ($(qsRowSelector, $(this)).length > tgtNumLists) {
            $(qsRowSelector, $(this)).last().remove();
        }

        // set desired values
        $(qsRowSelector, $(this)).each(function(index, element) {
            var tgtVal = '', tgtName = '';
            if (index < selections.length) {
                tgtVal = selections[index].tid;
                tgtName = selections[index].name;
            }
            $("input.mv-quicksearch-value", element).val(tgtVal);
            $("textarea.mv-quicksearch-display", element).val(tgtName);
            $("textarea.mv-quicksearch-display", element).removeData('prev_value');
        });
    });
});

/*
* jQuery UI Autocomplete HTML Extension
* start
*
* Copyright 2010, Scott Gonzalez (http://scottgonzalez.com)
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* http://github.com/scottgonzalez/jquery-ui-extensions
*/
(function( $ ) {

    var proto = $.ui.autocomplete.prototype,
        initSource = proto._initSource;

    function filter( array, term ) {
        var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
        return $.grep( array, function(value) {
            return matcher.test( $( "<div>" ).html( value.label || value.value || value ).text() );
        });
    }

    $.extend( proto, {
        _initSource: function() {
            if ( this.options.html && $.isArray(this.options.source) ) {
                this.source = function( request, response ) {
                    response( filter( this.options.source, request.term ) );
                };
            } else {
                initSource.call( this );
            }
        },

        _renderItem: function( ul, item) {
            return $( "<li></li>" )
                .data( "item.autocomplete", item )
                .append( $( "<div></div>" )[ this.options.html ? "html" : "text" ]( item.label ) )
                .appendTo( ul );
        }
    });

})( jQuery );
/*
* jQuery UI Autocomplete HTML Extension
* end
*/
